\chapter{模块划分与通信协议设计}
本章主要讨论系统设计的问题。首先描述了整个系统的设计思路，列出系统至少应该实现的基本功能，并根据功能进行模块划分，给出模块划分图。另外，还涉及到了通信组件设计中不可避免的通信协议设计问题，根据不同通信角色（注册中心，前台代码，设备逻辑微服务，对等的通信组件）给出通信需要建立的连接类型、传输的数据格式约定、主要字段的意义等信息。

本章的最后给出API 总表，列出系统完成后可被调用的 RESTful API 。

\section{设计思路}

如上所述，本通信组件采用的是对等实体通信模型（P2P 方式）。基于这个最基本的思路，一个完整的组件是同时包含了客户端和服务器端的，要实现的功能包括但不限于以下几方面：

\begin{enumerate}
	\item 正确接收来自设备逻辑模块的信息。考虑到中间的性能损耗 和信息传输的安全性考虑，最好能与逻辑容器建立 TCP连接，直接传输字节流或字符流的方式。所以，组件需要监听特定端口，通过这个端口接收来自逻辑容器的信息。
	\item 正确接收其他设备发过来的信息。系统采用 RESTful API 的方式处理设备之间的连接，中间涉及了 HTTP 请求的响应问题，包括了对不同 URI 子路径、不同的请求方法做出不同的响应等。因此通信组件要开放至少一个端口监听并接受 HTTP 连接请求。
	\item 能发起 HTTP 连接请求，将数据传送到目标设备。
	\item 将信息递交到设备逻辑模块。能创建与逻辑设备的 TCP连接并且将数据以字符流的形式传输。
	\item 向微服务注册中心递交查询请求，获取目标设备的 URI 地址。%需要扩展说明%
	\item 定时向注册中心报告设备当前的状态信息，在设备离线时能告知注册中心删除设备的相关信息。
    \item 暴露 API 供前端界面与设备进行交互，包括用户查询设备状态信息，设备接收用户定义的场景等。
	\item 传输失败时的错误处理。
\end{enumerate}

\section{软件模块划分}
	根据设计思路进行模块划分如下
\begin{enumerate}
	\item 与设备逻辑处理容器（物联网设备微服务）进行互联通信。
	\item 与其他设备的通信服务进行互联通信。
	\item 与注册中心的通信。
	\item 与前端界面（用户）的通信。
\end{enumerate}

\section{通信协议设计}
\subsection{ 与设备逻辑微服务的通信协议}
\subsubsection{基本设定}
建立连接类型：TCP 连接

传输的数据类型：字符流

传输的数据格式：json 格式

端口号：8974

\subsubsection{设备初始化}
设备刚开始运行（亦即将设备逻辑及通信组件微服务部署到设备中，设备启动，运行微服务并且接入网络时），通信组件微服务需要接收来自设备逻辑微服务发送的设备状态数据，格式为 json，其中至少包含以下字段：
\begin{itemize}
	\item Name：描述了本设备的名称
	\item ID：描述了本设备的 GUID 信息
	\item Type：描述了本设备的类型信息
	\item Status：描述了本设备的状态信息
\end{itemize}

\subsubsection{设备逻辑微服务需要向其他设备转发数据}

\paragraph{每次只给一个目标设备发送数据时：}

通信组件微服务需要接受来自设备逻辑微服务发送的、转发给其他设备的数据，格式为
json，至少包含以下两个字段：

\begin{itemize}
\item
  targetID：目标设备 id 信息，用于向注册中心查找目标设备的 URI 地址
\item
  targetName：目标设备名称。作为备选，在不知道目标设备的 ID
  时，需要利用这个字段向注册中心查找目标设备名字对应的 id 或 URI 。
\end{itemize}

将数据转发完毕后，向设备逻辑微服务发送``SUCCESS''表示发送成功。

因为网络、设备离线等原因造成传输失败时，向上层服务发送``failed''表示发送失败。


\paragraph{一次需要同时向多个设备发送数据时}

数据格式：JsonArray

数据样例：

{[}\{"targetid":"000001","mode":"morning","targetName":"light"\},

\{"targetid":"000022","mode":"safe","targetName":"camera"\}{]}

必须包含：targetId 字段。

连接类型：TCP 连接，socket 通信

数据转发完毕后，向设备逻辑微服务发送``success''表示发送成功。

出现传输失败的情况时，发送 failed 字样表示发送失败。

\paragraph{递交接收到的来自其他设备的信息时}

连接类型：TCP 连接，socket 通信

端口号：4096

数据格式：json 格式

\subsection{两个通信组件之间的通信协议设计}
\subsubsection{基本设定}
建立的连接类型：HTTP 连接

数据格式：json，封装在 HTTP 请求体当中。

请求方法：发送 PUT 请求

传输确认：条件码（201 Created）+响应消息体附加“SUCCESS”字符串，其中响应消息体内容直接上交到逻辑服务进行处理

目标 URI 的设计：http://ip:port/deviceLogic

\subsection{与注册中心的通信协议的设计}
\subsubsection{查找目标设备IP}
建立的连接类型：HTTP 连接

URI 格式：http://registryIP:port/ID/{deviceID}（根据 ID 查询）或http://registryIP:port/Name/{deviceName}（根据设备名称查询）

通过 URI 指定要查找的设备，不需要在消息体添加额外信息

返回的数据格式：json

返回数据至少包含以下字段：
\begin{itemize}
	\item id：目标设备的 id
	\item URI：目标设备的 URI
	\item Name：目标设备名字
\end{itemize}

查询结果：以 HTTP 状态码的方式代表查询结果。200为查询成功，404表示未找到资源，也就是查找失败。在查询成功时，直接根据查询结果转发数据。查询失败时，向上层设备报告。

\subsubsection{同时查找多个目标设备的 IP 时}
上一种查找 IP 的协议的设计，每次只可以查询一个设备的IP，在需要同时转发到多个设备时，只能连续发送多次查询请求，造成不必要的性能消耗。因此设计了适用于能一次查找到多个设备 IP 的通信协议。

URI 格式：http://registryIP:port/

请求方法：GET

因为 GET 方法中不能有请求消息体，所以通过自定义消息头的方式将要获取 IP 信息的 id 附加到消息头部中，键（key）部分为：“ids”，值部分是“\{“devices”:["id1","id2","id3"...]\}”的形式。

返回的数据类型：json 格式，数据样例如下：

\{"id1":"ip1","id2":"ip2","id3":"ip3"…\}

\subsubsection{递交设备状态信息}
连接类型：HTTP 连接

URI 格式：http://registryIP:Port/devices/ID/{deviceID}或http://registryIP:Port/

请求方法：PUT

通信间隔：5分钟

\subsection{与前端界面通信}
。。。

\subsection{API 列表}

\begin{verbatim}
http://ip:port/ 响应GET请求，获取设备状态信息

http://ip:port/deviceLogic 响应 PUT 请求，接收来自其他设备的数据

http://ip:port/interface 响应 PUT以及GET请求。\newline PUT 请求接收用户定义的情景链等信息，GET请求返回用户需要的信息

\end{verbatim}
